/**
 * 
 */
package de.mbenning.fsim.simulation.components;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.hibernate.ObjectNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import de.mbenning.fsim.domain.Saison;
import de.mbenning.fsim.domain.Spieler;
import de.mbenning.fsim.domain.SpielerStatistik;
import de.mbenning.fsim.persistence.dao.interfaces.IMainDAO;
import de.mbenning.fsim.persistence.dao.interfaces.ISpielerDAO;
import de.mbenning.fsim.simulation.components.api.ISpiel;
import de.mbenning.fsim.simulation.components.enums.HeimGastType;

/**
 * @author Martin.Benning
 *
 */
@Component ("spiel")
@Scope(value = "prototype")
public class Spiel extends Thread implements ISpiel {
	
	@Override
	public void run() {
		super.run();
		this.anpfiff();
	}

	private Aufstellung heim;
	private Aufstellung gast;
	private int spielminute = 0;
	private int halbzeit = 1;
	private int heimtore = 0;
	private int gasttore = 0;
	private int nachspielzeit = 0;
	private long simulationsgeschwindigkeit = 1000;
	private long halbzeitpause = 0;
	private List<String> torschuetzen = new ArrayList<String>();
	
	// DEBUG
	private int siegeHeim = 0;
	private int unentschieden = 0;
	private int siegeGast = 0;
	private int repeat = 1;
	private int toreh = 0;
	private int toreg = 0;
	private int null2null = 0;
	
	@Autowired
	private ISpielerDAO spielerDAO;
	
	@Autowired
	private IMainDAO mainDAO;
	
	private Saison saison;
	
	private Object outputElement;
	
	public Spiel() {
		
	}
	
	public Spiel(Aufstellung heim, Aufstellung gast) {
		this.heim = heim;
		this.gast = gast;
		this.saison = mainDAO.getSaison("2011/2012");
	}
	
	public void anpfiff() {
		this.saison = mainDAO.getSaison("2011/2012");
//		this.saison = new Saison();
//		this.saison.setSpielzeit("2011/2012");
//		mainDAO.store(saison);
		
		doAusgabe(heim.getVerein().getName() + " - " + gast.getVerein().getName() + "\t\t" + heimtore + ":" + gasttore);
		for(int i = 0; i < repeat; i++) {
			this.doSpielablauf();
		}
		doAusgabe("\n\nHeim: " + this.siegeHeim + " Unentschieden: " + this.unentschieden + " Gast: "+ siegeGast + " |  " + this.toreh + ":" + this.toreg);
		doAusgabe("HT/" + (this.toreh/repeat) + "|GT/" + (this.toreg/repeat));
		doAusgabe("0:0 = " + null2null);
	}
	
	public void doSpielablauf() {
		while(spielminute < (90+nachspielzeit)) {
			if(spielminute == (45+nachspielzeit)) {
				doAusgabe("Halbzeit");
				nachspielzeit = 0;
				halbzeit = 2;
				pause(halbzeitpause);
			}
			
			Aufstellung aufstellung = this.decisionMIT();
			doAusgabe(spielminute + ". Min | " + aufstellung.getVerein().getName() + " " + aufstellung.randomizeSpieler().getName());
			
			pause(simulationsgeschwindigkeit);
			
			if(decisionANG(aufstellung)) {
				doAusgabe("\t|--> " + aufstellung.randomizeSpieler().getName());
				pause(simulationsgeschwindigkeit);
				if(decisionANG(aufstellung)) {
					doAusgabe("\t\t|--> " + aufstellung.randomizeSpieler().getName());
					pause(simulationsgeschwindigkeit);
					if(decisionTOR(aufstellung)) {
						if(HeimGastType.HEIM.equals(aufstellung.getHeimGast())) {
							this.heimtore++;
							aufstellung.incTore();
						} else {
							this.gasttore++;
							aufstellung.incTore();
						}
						this.torschuetzen.add(this.heimtore + ":" + this.gasttore + " " + aufstellung.getCurrentSpieler().getName() + " (" + spielminute + ".)");
						System.out.print(" \t\t\t|--> " + aufstellung.getCurrentSpieler().getName());
						pause(simulationsgeschwindigkeit);
						doAusgabe(" => TOR!!!");
						this.postHandleTor(aufstellung.getCurrentSpieler());
					} else {
						System.out.print(" \t\t\t|--> " + aufstellung.getCurrentSpieler().getName());
						pause(simulationsgeschwindigkeit);
						doAusgabe(" => Chance vergeben!");
					}
				}
			}
			
			pause(simulationsgeschwindigkeit);
			spielminute++;
		}
		this.abpfiff();
	}
	
	public void abpfiff() {
		doAusgabe("ENDE");
		doAusgabe(heim.getVerein().getName() + " - " + gast.getVerein().getName() + "\t\t" + heimtore + ":" + gasttore + " (" + heim.getCount() + ":" + gast.getCount() + ")");
		for(String tor : this.torschuetzen) {
			doAusgabe(tor);
		}
		doAusgabe("====================================================================");
		if(this.heimtore > this.gasttore) this.siegeHeim++;
		if(this.heimtore < this.gasttore) this.siegeGast++;
		if(this.heimtore == this.gasttore) this.unentschieden++;
		if(this.heimtore == 0 && this.gasttore == 0) null2null++;
		this.toreh += this.heimtore;
		this.toreg += this.gasttore;
		this.heimtore = 0;
		this.gasttore = 0;
		this.spielminute = 0;
		this.torschuetzen.clear();
		this.halbzeit = 1;
	}
	
	private void postHandleTor(Spieler spieler) {
		SpielerStatistik stat = null;
		try {
			stat = spielerDAO.getSpielerStatistik(spieler, saison);
		} catch(ObjectNotFoundException e) {
			stat = new SpielerStatistik(spieler, saison);
		}
		stat.tore += 1;
		mainDAO.store(stat);
	}
	
	private Aufstellung decisionMIT() {
		int total = heim.getMittelfeld() + gast.getMittelfeld();
		
		Random rnd = new Random();
		int index = rnd.nextInt(total);
		
		if(index < heim.getMittelfeld()) {
			heim.incCount();
			return heim;
		} else {
			gast.incCount();
			return gast;
		}
	}
	
	private boolean decisionANG(Aufstellung aufstellung1) {
		Aufstellung aufstellung2 = this.getOtherAufstellung(aufstellung1);
		int total = aufstellung1.getAngriff() + aufstellung2.getAbwehr();
		Random rnd = new Random();
		int index = rnd.nextInt(total);
		if(index < aufstellung1.getAngriff()) {
			return true;
		}
		return false;
	}
	
	private boolean decisionTOR(Aufstellung aufstellung1) {
		Random rnd = new Random();
		int additionalIndex = rnd.nextInt(200);
		
		Aufstellung aufstellung2 = this.getOtherAufstellung(aufstellung1);
		int levelTor = aufstellung2.getSpieler().get(0).getLevel();
		int levelAng = aufstellung1.randomizeSpieler().getLevel(); 
		int total = (levelTor + levelAng + additionalIndex); // aufstellung2.getAbwehr() + 
		
		rnd = new Random();
		int index = rnd.nextInt(total);
		//doAusgabe(total + " - " + index + " | levelAng: " + levelAng);
		if(index < levelAng) {
			return true;
		}
		return false;
	}
	
	private Aufstellung getOtherAufstellung(Aufstellung aufstellung) {
		if(aufstellung.getVerein().equals(heim.getVerein())) {
			return gast;
		} else {
			return heim;
		}
	}
	
	private void handlePreTorActions(Aufstellung aufstellung) {
		
	}
	
	private void pause(long millis) {
		try {
			Thread.currentThread();
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} 
	}

	public Aufstellung getHeim() {
		return heim;
	}

	public void setHeim(Aufstellung heim) {
		this.heim = heim;
	}

	public Aufstellung getGast() {
		return gast;
	}

	public void setGast(Aufstellung gast) {
		this.gast = gast;
	}

	public IMainDAO getMainDAO() {
		return mainDAO;
	}

	public void setMainDAO(IMainDAO mainDAO) {
		this.mainDAO = mainDAO;
	}

	public ISpielerDAO getSpielerDAO() {
		return spielerDAO;
	}

	public void setSpielerDAO(ISpielerDAO spielerDAO) {
		this.spielerDAO = spielerDAO;
	}

	@Override
	public void doAusgabe(String text) {
		System.out.println(text);
	}

	public Object getOutputElement() {
		return outputElement;
	}

	public void setOutputElement(Object outputElement) {
		this.outputElement = outputElement;
	}
	
}
